// SPDX-License-Identifier: GPL-2.0 or GPL-3.0
// Copyright © 2018-2019 Ariadne Devos
/* sHT -- architecture-independent compiler magic */

#ifndef _sHT_COMPILER_H
#define _sHT_COMPILER_H

/* Clang or GCC is assumed, see Bug #3 */

#define sHT_likely(b) (__builtin_expect(!!(b), 1))
#define sHT_unlikely(b) (__builtin_expect(!!(b), 0))

/** Can the compiler prove @var{u} is a constant?
  There may be false negatives. */
#define sHT_constant_p(u) __builtin_constant_p(u)

/* Let the compiler forget the value of the variable var.
   This does not avoid speculation by the processor.
   For Spectre mitigations, consider sHT_despeculate.

   @var{var} must not be const-qualified. */
#define sHT_hide_var(var) \
	do { \
		__asm__("" : "=r" (var) : "0" (var)); \
	} while (0)

/** Let the compiler believe that value of the variable @var{var} depends upon
  @var{dependency}.

  Afterwards, the value of @var{var} will be supposedly-dependant upon the
  value of @var{dependency}.

  @var{var} and @var{dependency} must not be const-qualified. */
#define sHT_depend(var, dependency) \
	do { \
		__asm__("" : "=X" (var) : "X" (var), "X" (dependency)); \
	} while (0)

/** Return @var{val} unchanged, supposedly-dependant upon the value of
  @var{dependency}.

  Afterwards, the value of @var{var} will be supposedly-dependant upon the
  value of @var{dependency}.

  @var{var} and @var{dependency} must not be const-qualified. */
#define sHT_depending(val, dependency) \
	({ __typeof__(val) _sHT_dep_val = (val); \
	sHT_depend(_sHT_dep_val, dependency); \
	_sHT_dep_val; })

/** Evaluate the boolean expression @var{cond}.

  @var{cond}: a boolean expression variable in @var{var}
  @var{var}: a variable to test, may not be const-qualified

  In contrast to a plain C @code{if}, the compiler will not
  assume the correct branch is taken on a speculative execution.

  Its speculative value will be returned. */
#define sHT_test_hidden(var, cond) \
	((cond) ? ({ sHT_hide_var(var); (_Bool) 1; }) \
	: ({ sHT_hide_var(var); (_Bool) 0; }))

/** Evaluate the boolean expression @var{cond}

  @var{cond}: a boolean expression variable in @var{var}
  @var{x}: a variable to test, may not be const-qualified
  @var{y}: another variable to test, may not be const-qualified

  In contrast to a plain C @code{if}, the compiler will not
  assume the correct branch is taken on a speculative execution.

  Its speculative value will be returned. */
#define sHT_test_hidden2(x, y, cond) \
	({\
		_Bool _sHT_test_hidden2_ret = (cond); \
		sHT_hide_var(x); \
		sHT_hide_var(y); \
		_sHT_test_hidden2_ret; \
	})

/** Reverse taking a pointer to a member.

  @var{ptr}: a valid pointer, pointing to an instance of the member
    denoted by @var{member}.
  @var{type}: a C union or struct type, possibly as a typedef
  @var{member}: the name of a member of @var{type}

  This concept is taken from Linux.
  TODO: compatibility with Intel MMX and other pointer bounds checkers.

  Return a pointer to the @var{type} structure, of which a pointer to its
  field @var{member} is equal to @var{ptr}. */
#define sHT_container_of(ptr, type, member) \
  ((type *) (((char *) ptr) - offsetof(type, member)))

/** Something has gone wrong, stop the current process.

  This is only for catching bugs. In particular, it may speculatively
  be ignored. (Replacing a possibly repeating bug with a crashing
  speculation bug is, from a security perspective, probably fine.)

 @var{msg}: a literal string, describing what should have been the case. */
#define sHT_halt(msg) __builtin_trap();

#endif
